<?php

require_once __DIR__.'/func.php';
require_once __DIR__.'/mysql.php';

class generator {

  const TEAMUG_VERSION = '1.0';
  const TEAMUG_GENERATOR_VERSION = '1.0';

  private $htaccessNoRewrite = array();
  private $mysqlDatabases = array();
  private $sessionVars = array();
  private $configVars = array();
  private $appFilename;
  private $namespaceApp;
  private $namespaceOthers;
  private $pathTeamug;
  private $installTo;
  private $pages;

  public function __construct($appFilename, $installTo, $namespace) {

    if (substr($installTo,-1)!=='/') { $installTo.= '/'; }
    $this->installTo = $installTo;

    $this->namespaceApp = $namespace;
    $this->appFilename = $appFilename;
  }
    
  
  public function createApp() {

    $this->writeHtaccess();
    $this->writePages();
    $this->writeDataClasses();
    
    $mysql = $this->createAppMysql();
    $session = $this->createAppSession();
    $config = $this->createAppConfig();
    $this->writeApp($mysql, $session, $config);
  }


  public function htaccess(){
    $this->htaccessNoRewrite = func_get_args();
    $this->write('You requested rewrite will exclude your directories: '.implode(',', $this->htaccessNoRewrite));
  }

  
  public function mysql($id, $host, $user, $password, $database) {
    $this->mysqlDatabases[$id] = 
      array('host'=>$host, 'user'=>$user, 'password'=>$password, 'database'=>$database);
  }


  public function session() {
    $this->sessionVars = func_get_args();
    $this->write('You requested $_SESSION will contain vars: '.implode(',', $this->sessionVars));
  }

  
  public function config() {
    $this->configVars = func_get_args();
    $this->write('You requested config will contain vars: '.implode(',', $this->configVars));
  }


  public function otherNamespace($namespace, $directory) {
    $this->namespaceOthers[$namespace] = $directory;
    $this->write("You requested namespace:{$namespace} relates to directory:{$directory}");
  }


  public function pathToTeamug($path) {
    $this->pathTeaMug = $path;
    $this->write("You stated path to teamug:{$path}");
  }

  public function pages() {
    $this->pages = func_get_args();
    $this->write('You stated pages to create are:'.implode(',', $this->pages));
  }
  
  

  public function writeHtaccess() {
    
    $this->write('Writing .htaccess');
    
    $f='';
    foreach($this->htaccessNoRewrite AS $folder) {
      $f.= "RewriteRule ^$folder/(.*)$ /$folder/$1 [L]\n";
    }
    $r = "RewriteRule ^(.*)$ {$this->appFilename}\n";
    $this->writeFile('.htaccess', 'tpl_htaccess.txt', array(
      'folders_to_ignore'=>$f, 
      'rewrite_to_app'=>$r));
  }

  
  private function writeDataClasses() {

    $this->ensureFolder('data', 0755);

    foreach($this->mysqlDatabases AS $id => $db) {
      $mysql = new mysql($db['host'], $db['user'], $db['password'],$db['database']);
      $tables = $mysql->getTables();
      $this->ensureFolder("data/$id", 0755);
      $this->ensureFolder("data/$id/mysql", 0755);
      foreach($tables AS $table) {
        $class = func::ucName($table);
        $this->makeDataStructure($mysql, $id, $class, $table);
        $this->makeMysqlDataAccess($id, $class, $table);
      }
    }
  }
  
  

  private function makeDataStructure($mysql, $id, $class, $table) {

    $this->write(" Writing data structure:$class, to represent table:$table");
    
    $fields = $mysql->getFields($table);
    $replacements = array(
      'kind' => $class,
      'properties' => 'protected $'.implode(";\n  protected \$", $fields).";\n",
      'namespace' => '/'.$this->namespaceApp.'/data'
    );
    $this->writeFile("data/$id/$class.php", 'tpl_DataStructure.php', $replacements);
  }
  
  
  private function makeMysqlDataAccess($id, $class, $table) {
    $this->write(" Writing data access:$class, to manage mysql db table:$table");
    
    $replacements = array(
      'kind' => $class,
      'namespace' => '/'.$this->namespaceApp.'/data/mysql',
      'data_structure_namespace' => '/'.$this->namespaceApp.'/data/'
    );
    $this->writeFile("data/$id/mysql/$class.php", 'tpl_DataAccessMysql.php', $replacements);
  }

  
  public function writePages() {

    foreach($this->pages AS $page) {
      $class = func::ucName($page);
      $this->write("Writing request handler:$class for page:$page");      
      $replacements = array(
        'class' => $class,
        'namespace' => $this->namespaceApp
      );
      $this->writeFile($class.'.php', 'tpl_RequestHandler.php', $replacements);
    }
  }

  private function writeApp($mysql, $session, $config) {
    $replacements = array(
        'path_to_teamug' => $this->pathTeamug,
        'namespace' => $this->namespaceApp,
        
    
      );
      $this->writeFile($class.'.php', 'tpl_RequestHandler.php', $replacements);
  }

  
  
  
  
  private function createAppMysql() {
    
    $code='';
    
    foreach($this->mysqlDatabases AS $id => $connection_details) {
      extract($connection_details);
      $code.= "mysqli::declareConnection('$id', '$host', '$user', '$password', '$database');\n";
    }
    return $code;
  }
  
  private function createAppSession() {
  
    $code="if (count(\$_SESSION)===0) {";
    
    foreach($this->sessionVars AS $var) {
      $code.= "  session::setDefault('$var', null);\n";
    }
    $code.= "}\n";
    return $code;
  }

  private function createAppConfig() {

    $code='';
    
    foreach($this->configVars AS $var) {
      $code.= "config::add('$var', null);\n";
    }
    return $code;
  }

  
  private function writeFile($filename, $templateName, $replacements) {

    $filePath = $this->installTo.$filename;
    
    // Get content and replace tokens
    $content = file_get_contents(__DIR__."/$templateName");
    foreach($replacements AS $k => $v) {
      $content = str_replace("@@$k@@", $v, $content);
    }
    
    $content = str_replace('@@TEAMUG_VERSION@@', self::TEAMUG_VERSION, $content);
    $content = str_replace('@@TEAMUG_GENERATOR_VERSION@@', self::TEAMUG_GENERATOR_VERSION, $content);    
    
    // Write file
    $fp = fopen($filePath, 'w');
    if ($fp===false) { $this->writeAndExit("Failed to open $filePath for writing.\nCheck folder permissions etc"); }

    $byte_cnt = fwrite($fp, $content);
    if ($byte_cnt===false) { $this->writeAndExit("Failed to write to $filePath.\nCheck folder permissions etc"); }

    $this->write("File:$filePath written successfully");

    fclose($fp);
  }
 
  
  private function ensureFolder($path, $permissions) {
    $folder = $this->installTo.$path;
    if (!file_exists($folder)) { 
      $ok = mkdir($folder, $permissions); 
      if (!$ok) {
        $this->writeAndExit("Could not mkdir on $path.\nCheck folder permissions etc");
      }
    }
    $this->write("Directory:$path has been created with permissions:".decoct($permissions)); 
  }

  
  private function write($message) {
    echo "{$message}\n";
  }
  
  
  private function writeAndExit($message) {
    $this->write($message);
    $this->write("80( Script aborts here\n");
    exit;
  }

  
  
  
  
}

